/*
    kOTF Open Trace Format - a library for generating execution traces.
    Copyright 2012 Daniel K. O.

    kOTF is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    kOTF is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with kOTF.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <kotf/StreamHelpers.hpp>
#include <kotf/Session.hpp>

namespace kotf {

    Scope::Scope(Stream& s, const State& st, size_t startTag) :
        stream(s),
        state(st),
        finishTag(startTag)
    {
        stream.push(state, startTag);
    }

    Scope::Scope(Stream& s, const std::string& stname, size_t startTag) :
        stream(s),
        state(s.getSession().getState(stname)),
        finishTag(startTag)
    {
        stream.push(state, startTag);
    }

    Scope::Scope(Stream* s, const State& st, size_t startTag) :
        stream(*s),
        state(st),
        finishTag(startTag)
    {
        stream.push(state, startTag);
    }

    Scope::Scope(Stream* s, const std::string& stname, size_t startTag) :
        stream(*s),
        state(stream.getSession().getState(stname)),
        finishTag(startTag)
    {
        stream.push(state, startTag);
    }

    Scope::Scope(const std::string& stname, size_t startTag) :
        stream(Stream::mine()),
        state(stream.getSession().getState(stname)),
        finishTag(startTag)
    {
        stream.push(state, startTag);
    }

    Scope::Scope(const State& st, size_t startTag) :
        stream(Stream::mine()),
        state(st),
        finishTag(startTag)
    {
        stream.push(state, startTag);
    }

    Scope::~Scope()
    {
        stream.pop(state, finishTag);
    }

    void
    Scope::change(const State& newst)
    {
        stream.change(state, newst);
        state = newst;
    }


    ScopedLock::ScopedLock(Stream& s, const Counter& cnt) :
        stream(s), counter(cnt)
    {
        stream.update(counter, 1);
    }

    ScopedLock::ScopedLock(Stream& s, const std::string& cnt) :
        stream(s),
        counter(stream.getSession().getCounter(cnt))
    {
        stream.update(counter, 1);
    }

    ScopedLock::ScopedLock(Stream* s, const Counter& cnt) :
        stream(*s), counter(cnt)
    {
        stream.update(counter, 1);
    }

    ScopedLock::ScopedLock(Stream* s, const std::string& cnt) :
        stream(*s),
        counter(stream.getSession().getCounter(cnt))
    {
        stream.update(counter, 1);
    }


    ScopedLock::ScopedLock(const Counter& cnt) :
        stream(Stream::mine()), counter(cnt)
    {
        stream.update(counter, 1);
    }

    ScopedLock::ScopedLock(const std::string& cnt) :
        stream(Stream::mine()), counter(stream.getSession().getCounter(cnt))
    {
        stream.update(counter, 1);
    }

    void
    ScopedLock::locked()
    {
        stream.update(counter, 2);
    }
    
    ScopedLock::~ScopedLock()
    {
        stream.update(counter, 0);
    }

    
    Condition::Condition(Stream& s, const State& st,
                         const Channel& ch, uint64_t len, uint64_t t) :
        stream(s),
        state(st),
        chan(ch),
        length(len),
        tag(t),
        waiting(false)
    {}

    void
    Condition::wait()
    {
        if (!waiting) {
            waiting = true;
            stream.push(state);
        }
    }

    void
    Condition::done()
    {
        if (waiting) {
            stream.pop(state);
            stream.recv(chan, length, tag);
        }
    }
}
